package com.kingmed.kmss.auth.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.kingmed.kmss.auth.service.AuthService;
import com.kingmed.kmss.auth.service.WeaverService;
import com.kingmed.kmss.common.dto.admin.ums.AdminDTO;
import com.kingmed.kmss.common.dto.admin.ums.AdminLoginDTO;
import com.kingmed.kmss.common.dto.admin.ums.LoginUserDTO;
import com.kingmed.kmss.common.dto.auth.CustomMessageReq;
import com.kingmed.kmss.common.satoken.LoginHelper;
import com.kingmed.kmss.common.service.sys.RedisService;
import com.kingmed.kmss.common.vo.CommonResponse;
import com.kingmed.kmss.common.vo.CommonResponseHelper;
import com.kingmed.kmss.framework.cpwx.service.KmWxCpOAuth2Service;
import com.kingmed.kmss.framework.feign.client.admin.CommonAdminFeignServiceFacade;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
import org.apache.http.util.Asserts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户统一认证和授权中心
 */
@Slf4j
@RestController
@RequestMapping("/")
@Api(tags = "auth用户统一认证和授权中心")
public class AuthController {

    @Autowired
    private AuthService authService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private WeaverService weaverService;
    @Autowired
    private KmWxCpOAuth2Service kmWxCpOAuth2Service;
    @Autowired
    private CommonAdminFeignServiceFacade adminFeignServiceFacade;

    @Value("${sa-token.token-name}")
    private String TOKEN_HEAD;

    private static final String REDIS_PREFIX = "Authorization:login:failure:";

    // 账号封禁时间 秒
    private static final int LOCK_MINUTE = 5;
    private static final int LOCK_SECOND = 60 * LOCK_MINUTE;

    /**
     * 登陆失败次数过期时间
     */
    private static final int LOGIN_FAILS_TIME = 3 * 60 * 60;

    // 允许错误登录次数
    private static final int LOGIN_FAIL_TIMES = 5;

    @ApiOperation(value = "用户登录（用户名密码）")
    @PostMapping(value = "login")
    @ResponseBody
    public CommonResponse<?> login(@RequestBody AdminLoginDTO adminLoginDto) {
        // 登录出错次数
        Integer loginFailTimes = redisService.get(REDIS_PREFIX + adminLoginDto.getUsername()) == null
                ? Integer.valueOf(0) : (Integer) redisService.get(REDIS_PREFIX + adminLoginDto.getUsername());
        // true=已被封禁, false=未被封禁
        boolean isDisable = StpUtil.isDisable(adminLoginDto.getUsername());
        if (isDisable) {
            // 指定账号剩余封禁时间，单位：秒
            long disableTime = StpUtil.getDisableTime(adminLoginDto.getUsername());
            long minute = disableTime / 60;
            long second = disableTime % 60;
            return CommonResponseHelper.unauthorized("连续登录失败" + LOGIN_FAIL_TIMES + "次已锁定，请" + minute + "分" + second + "秒后再试");
        }
        // 登录验证
        String token = authService.login(adminLoginDto);
        Map<String, Object> tokenMap = new HashMap<>();
        if (CharSequenceUtil.isNotBlank(token)) {
            tokenMap.put("token", token);
            tokenMap.put("tokenHead", TOKEN_HEAD);
            LoginUserDTO loginUser = LoginHelper.getLoginUser();
            tokenMap.put("username", loginUser.getUsername());
            tokenMap.put("nickName", loginUser.getNickName());
            // 删除登录出错次数
            redisService.del(adminLoginDto.getUsername());
            return CommonResponseHelper.success("登录成功", tokenMap);
        } else {
            // 连续登录出错锁账号一段时间
            loginFailTimes = loginFailTimes + 1;
            redisService.set(REDIS_PREFIX + adminLoginDto.getUsername(), loginFailTimes, LOGIN_FAILS_TIME);
        }
        // 错误5次锁定
        if (loginFailTimes == LOGIN_FAIL_TIMES) {
            StpUtil.disable(adminLoginDto.getUsername(), LOCK_SECOND);
            redisService.del(REDIS_PREFIX + adminLoginDto.getUsername());
            return CommonResponseHelper.unauthorized("连续登录失败" + LOGIN_FAIL_TIMES + "次将锁定" + LOCK_MINUTE + "分钟");
        }
        return CommonResponseHelper.unauthorized("登录失败，用户名或者密码错误");
    }

    @ApiOperation(value = "解锁连续登录失败用户")
    @GetMapping(value = "sms/effect")
    public CommonResponse<?> effectUser(@RequestParam String username) {
        StpUtil.untieDisable(username);
        return CommonResponseHelper.success("解锁成功");
    }

    @ApiOperation(value = "OA单点登录")
    @GetMapping(value = "oa/login")
    public CommonResponse<?> oaLogin(HttpServletRequest request, HttpServletResponse response, @RequestParam String ticket) throws IOException {
        String redirectUrl = authService.oaLogin(ticket);
        if (CharSequenceUtil.isNotBlank(redirectUrl)) {
            response.sendRedirect(redirectUrl);
        }
        return null;
    }

    @ApiOperation(value = "OA移动端单点登录")
    @GetMapping(value = "oa/mobile/login")
    public CommonResponse<?> oaSalesLogin(HttpServletRequest request, HttpServletResponse response, @RequestParam String ticket) throws IOException {
        String redirectUrl = authService.oaSalesLogin(ticket);
        if (CharSequenceUtil.isNotBlank(redirectUrl)) {
            response.sendRedirect(redirectUrl);
        }
        return null;
    }

    @ApiOperation(value = "企业微信单点登录（PC）")
    @GetMapping(value = "cpwx/pc/login")
    public CommonResponse<?> cpwxPcLogin(HttpServletResponse response, @RequestParam String code, @RequestParam Integer agentId) throws IOException {
        String redirectUrl = authService.cpwxPcLogin(code,agentId);
        if (CharSequenceUtil.isNotBlank(redirectUrl)) {
            response.sendRedirect(redirectUrl);
        }
        return null;
    }

    @ApiOperation(value = "企业微信单点登录(移动端)")
    @GetMapping(value = "cpwx/client/login")
    public CommonResponse<?> cpwxClientLogin(HttpServletResponse response, @RequestParam String code, @RequestParam Integer agentId) throws IOException {
        String redirectUrl = authService.cpwxClientLogin(code,agentId);
        if (CharSequenceUtil.isNotBlank(redirectUrl)) {
            response.sendRedirect(redirectUrl);
        }
        return null;
    }

    @ApiOperation(value = "短信登录（预留）")
    @RequestMapping(value = "sms/login", method = RequestMethod.POST)
    @ResponseBody
    public CommonResponse<?> smsLogin(@RequestBody AdminLoginDTO adminLoginDto) {
        return CommonResponseHelper.success("登录成功");
    }

    @ApiOperation(value = "OA发消息")
    @PostMapping(value = "oa/sendMsg")
    public CommonResponse<?> sendOaMsg(@RequestBody CustomMessageReq customMessageReq) {
        String resp = weaverService.sendCustomMessageSingle(customMessageReq);
        return CommonResponseHelper.success(resp);
    }


    @ApiOperation(value = "企业微信的应用回调")
    @GetMapping(value = "cpwx/agent/callback")
    public void getToken(HttpServletResponse response, @RequestParam String code, @RequestParam String bizUrl, @RequestParam Integer agentId) throws Exception {
        log.info("回调code:{}", code);
        // 获取工号
        WxCpOauth2UserInfo authUserInfo = kmWxCpOAuth2Service.getUserInfo(agentId, code);
        log.info("获取用户信息：{}", authUserInfo);
        String userId = authUserInfo.getUserId();
        Asserts.notBlank(userId, "用户信息异常:" + userId);
        AdminDTO adminDTO = adminFeignServiceFacade.getUserByUserNum(userId);
        Asserts.notNull(adminDTO, "该用户信息不存在，id：" + userId);
        // 获取token
        String token = authService.unAuthLogin(adminDTO.getUsername());
        // 重定向
        String decodeUrl = URLDecoder.decode(bizUrl, "UTF-8");
        String redirectUrl = decodeUrl + "&token=" + token + "&username=" + adminDTO.getId();
        log.info("审批页面重定向URL：{}", redirectUrl);
        // 重定向拼接url
        response.sendRedirect(redirectUrl);
    }

}
